package pers.cfeng.server.dataManage.dataItem;

import pers.cfeng.common.SubArray;
import pers.cfeng.server.dataManage.DataManagerImpl;
import pers.cfeng.server.dataManage.page.Page;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 数据项： 封装的数据对象
 * 使用读写锁进行数据库文件的读写
 * 上层调用时，修改之前调用before进行备份，撤销修改数据恢复unbefore，修改完成后调用after
 */

public class DataItemImpl implements DataItem {
    private SubArray raw;
    private byte[] oldRaw;
    private Lock rLock;//读锁
    private Lock wLock;
    private DataManagerImpl dm;
    private long uid;
    private Page page;

    public DataItemImpl(SubArray raw, byte[] oldRaw, Page page, long uid, DataManagerImpl dm) {
        this.raw = raw;
        this.oldRaw = oldRaw;
        ReadWriteLock lock = new ReentrantReadWriteLock();
        rLock = lock.readLock();
        wLock = lock.writeLock();
        this.dm = dm;
        this.uid = uid;
        this.page = page;
    }

    public boolean isValid() {
        return raw.raw[raw.start + DataItemConstant.OFFSET_VALID] == (byte) 0;
    }

    @Override
    public SubArray data() {
        return new SubArray(raw.raw, raw.start + DataItemConstant.OFFSET_DATA, raw.end);
    }

    /**
     * 开始将数据写道oldraw中存储
     */
    @Override
    public void before() {
        wLock.lock();//写锁
        page.setModified(true);
        System.arraycopy(raw.raw, raw.start, oldRaw,0, oldRaw.length);
    }

    /**
     * 旧将oldRaw放回去
     */
    @Override
    public void unBefore() {
        System.arraycopy(oldRaw, 0, raw.raw, raw.start, oldRaw.length);
        wLock.unlock();
    }

    @Override
    public void after(long tid) {
        //日志
        dm.logDataItem(tid, this);
        wLock.unlock();
    }

    @Override
    public void release() {
        dm.releaseDataItem(this);
    }

    @Override
    public void lock() {
        wLock.lock();
    }

    @Override
    public void unLock() {
        wLock.unlock();
    }

    @Override
    public void rLock() {
        rLock.lock();
    }

    @Override
    public void rUnLock() {
        rLock.unlock();
    }

    @Override
    public Page page() {
        return page;
    }

    @Override
    public long getUid() {
        return uid;
    }

    @Override
    public byte[] getOldRaw() {
        return oldRaw;
    }

    @Override
    public SubArray getRaw() {
        return raw;
    }
}
